/*uses class "ghost-text-message" instead of "humane"*/
/*uses name "GThumane" instead of "humane"*/
/**
 * humane.js 3.2.0
 * Humanized Messages for Notifications
 * @author Marc Harter (@wavded)
 * @example
 *   humane.log('hello world');
 * See more usage examples at: http://wavded.github.com/humane-js/
 */

;!function (name, context, definition) {
	if (typeof module !== 'undefined') module.exports = definition(name, context)
	else if (typeof define === 'function' && typeof define.amd  === 'object') define(definition)
	else context[name] = definition(name, context)
}('GThumane', this, function (name, context) {
	var win = window
	var doc = document

	var ENV = {
		 on: function (el, type, cb) {
				'addEventListener' in win ? el.addEventListener(type,cb,false) : el.attachEvent('on'+type,cb)
		 },
		 off: function (el, type, cb) {
				'removeEventListener' in win ? el.removeEventListener(type,cb,false) : el.detachEvent('on'+type,cb)
		 },
		 bind: function (fn, ctx) {
				return function () { fn.apply(ctx,arguments) }
		 },
		 isArray: Array.isArray || function (obj) { return Object.prototype.toString.call(obj) === '[object Array]' },
		 config: function (preferred, fallback) {
				return preferred != null ? preferred : fallback
		 },
		 transSupport: false,
		 useFilter: /msie [678]/i.test(navigator.userAgent), // sniff, sniff
		 _checkTransition: function () {
				var el = doc.createElement('div')
				var vendors = { webkit: 'webkit', Moz: '', O: 'o', ms: 'MS' }

				for (var vendor in vendors)
					 if (vendor + 'Transition' in el.style) {
							this.vendorPrefix = vendors[vendor]
							this.transSupport = true
					 }
		 }
	}
	ENV._checkTransition()

	var GThumane = function (o) {
		 o || (o = {})
		 this.queue = []
		 this.baseCls = o.baseCls || 'ghost-text-message'
		 this.addnCls = o.addnCls || ''
		 this.timeout = 'timeout' in o ? o.timeout : 2500
		 this.waitForMove = o.waitForMove || false
		 this.clickToClose = o.clickToClose || false
		 this.timeoutAfterMove = o.timeoutAfterMove || false
		 this.container = o.container

		 try { this._setupEl() } // attempt to setup elements
		 catch (e) {
			 ENV.on(win,'load',ENV.bind(this._setupEl, this)) // dom wasn't ready, wait till ready
		 }
	}

	GThumane.prototype = {
		 constructor: GThumane,
		 _setupEl: function () {
				var el = doc.createElement('div')
				el.style.display = 'none'
				if (!this.container){
					if(doc.body) this.container = doc.body;
					else throw 'document.body is null'
				}
				this.container.appendChild(el)
				this.el = el
				this.removeEvent = ENV.bind(function(){ if (!this.timeoutAfterMove){this.remove()} else {setTimeout(ENV.bind(this.remove,this),this.timeout);}},this)
				this.transEvent = ENV.bind(this._afterAnimation,this)
				this._run()
		 },
		 _afterTimeout: function () {
				if (!ENV.config(this.currentMsg.waitForMove,this.waitForMove)) this.remove()

				else if (!this.removeEventsSet) {
					 ENV.on(doc.body,'mousemove',this.removeEvent)
					 ENV.on(doc.body,'click',this.removeEvent)
					 ENV.on(doc.body,'keypress',this.removeEvent)
					 ENV.on(doc.body,'touchstart',this.removeEvent)
					 this.removeEventsSet = true
				}
		 },
		 _run: function () {
				if (this._animating || !this.queue.length || !this.el) return

				this._animating = true
				if (this.currentTimer) {
					 clearTimeout(this.currentTimer)
					 this.currentTimer = null
				}

				var msg = this.queue.shift()
				var clickToClose = ENV.config(msg.clickToClose,this.clickToClose)

				if (clickToClose) {
					 ENV.on(this.el,'click',this.removeEvent)
					 ENV.on(this.el,'touchstart',this.removeEvent)
				}

				var timeout = ENV.config(msg.timeout,this.timeout)

				if (timeout > 0)
					 this.currentTimer = setTimeout(ENV.bind(this._afterTimeout,this), timeout)

				if (ENV.isArray(msg.html)) msg.html = '<ul><li>'+msg.html.join('<li>')+'</ul>'

				this.el.innerHTML = msg.html
				this.currentMsg = msg
				this.el.className = this.baseCls
				if (ENV.transSupport) {
					 this.el.style.display = 'block'
					 setTimeout(ENV.bind(this._showMsg,this),50)
				} else {
					 this._showMsg()
				}

		 },
		 _setOpacity: function (opacity) {
				if (ENV.useFilter){
					 try{
							this.el.filters.item('DXImageTransform.Microsoft.Alpha').Opacity = opacity*100
					 } catch(err){}
				} else {
					 this.el.style.opacity = String(opacity)
				}
		 },
		 _showMsg: function () {
				var addnCls = ENV.config(this.currentMsg.addnCls,this.addnCls)
				if (ENV.transSupport) {
					 this.el.className = this.baseCls+' '+addnCls+' '+this.baseCls+'-animate'
				}
				else {
					 var opacity = 0
					 this.el.className = this.baseCls+' '+addnCls+' '+this.baseCls+'-js-animate'
					 this._setOpacity(0) // reset value so hover states work
					 this.el.style.display = 'block'

					 var self = this
					 var interval = setInterval(function(){
							if (opacity < 1) {
								 opacity += 0.1
								 if (opacity > 1) opacity = 1
								 self._setOpacity(opacity)
							}
							else clearInterval(interval)
					 }, 30)
				}
		 },
		 _hideMsg: function () {
				var addnCls = ENV.config(this.currentMsg.addnCls,this.addnCls)
				if (ENV.transSupport) {
					 this.el.className = this.baseCls+' '+addnCls
					 ENV.on(this.el,ENV.vendorPrefix ? ENV.vendorPrefix+'TransitionEnd' : 'transitionend',this.transEvent)
				}
				else {
					 var opacity = 1
					 var self = this
					 var interval = setInterval(function(){
							if(opacity > 0) {
								 opacity -= 0.1
								 if (opacity < 0) opacity = 0
								 self._setOpacity(opacity);
							}
							else {
								 self.el.className = self.baseCls+' '+addnCls
								 clearInterval(interval)
								 self._afterAnimation()
							}
					 }, 30)
				}
		 },
		 _afterAnimation: function () {
				if (ENV.transSupport) ENV.off(this.el,ENV.vendorPrefix ? ENV.vendorPrefix+'TransitionEnd' : 'transitionend',this.transEvent)

				if (this.currentMsg.cb) this.currentMsg.cb()
				this.el.style.display = 'none'

				this._animating = false
				this._run()
		 },
		 remove: function (e) {
				var cb = typeof e == 'function' ? e : null

				ENV.off(doc.body,'mousemove',this.removeEvent)
				ENV.off(doc.body,'click',this.removeEvent)
				ENV.off(doc.body,'keypress',this.removeEvent)
				ENV.off(doc.body,'touchstart',this.removeEvent)
				ENV.off(this.el,'click',this.removeEvent)
				ENV.off(this.el,'touchstart',this.removeEvent)
				this.removeEventsSet = false

				if (cb && this.currentMsg) this.currentMsg.cb = cb
				if (this._animating) this._hideMsg()
				else if (cb) cb()
		 },
		 log: function (html, o, cb, defaults) {
				var msg = {}
				if (defaults)
					for (var opt in defaults)
							msg[opt] = defaults[opt]

				if (typeof o == 'function') cb = o
				else if (o)
					 for (var opt in o) msg[opt] = o[opt]

				msg.html = html
				if (cb) msg.cb = cb
				this.queue.push(msg)
				this._run()
				return this
		 },
		 spawn: function (defaults) {
				var self = this
				return function (html, o, cb) {
					 self.log.call(self,html,o,cb,defaults)
					 return self
				}
		 },
		 create: function (o) { return new GThumane(o) }
	}
	return new GThumane()
})
